package com.h5ve.flow.controller;

import cn.dev33.satoken.annotation.SaCheckPermission;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.h5ve.base.api.R;
import com.h5ve.base.constant.CommonConstants;
import com.h5ve.base.util.StrUtil;
import com.h5ve.data.vo.WarmFlowInteractiveTypeVo;
import com.h5ve.flow.service.ExecuteService;
import com.h5ve.flow.service.HhDefService;
import com.h5ve.flow.vo.FlowHisTaskVo;
import com.h5ve.flow.vo.FlowTaskVo;
import com.h5ve.security.entity.H5veUser;
import com.h5ve.security.util.SecurityUtil;
import com.h5ve.system.entity.Dept;
import com.h5ve.system.entity.Role;
import com.h5ve.system.service.DeptService;
import com.h5ve.system.service.RoleService;
import com.warm.flow.core.FlowFactory;
import com.warm.flow.core.constant.FlowCons;
import com.warm.flow.core.entity.*;
import com.warm.flow.core.enums.CooperateType;
import com.warm.flow.core.enums.NodeType;
import com.warm.flow.core.enums.UserType;
import com.warm.flow.core.service.*;
import com.warm.flow.core.utils.StreamUtils;
import com.warm.flow.orm.entity.FlowHisTask;
import com.warm.flow.orm.entity.FlowTask;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * 流程实例Controller
 *
 * @author hh
 * @date 2023-04-18
 */
@Slf4j
@Validated
@RestController
@RequestMapping("/flow/execute")
public class ExecuteController {
    @Resource
    private com.h5ve.system.service.UserService userService;

    @Resource
    private DeptService deptService;

    @Resource
    private RoleService roleService;

    @Resource
    private HisTaskService hisTaskService;

    @Resource
    private TaskService taskService;

    @Resource
    private NodeService nodeService;

    @Resource
    private InsService insService;

    @Resource
    private UserService flowUserservice;

    @Resource
    private ExecuteService executeService;

    @Resource
    private HhDefService hhDefService;

    /**
     * 分页待办任务列表
     */
    @SaCheckPermission("execute_todo")
    @GetMapping("/toDoPage")
    public R toDoPage(Page page, FlowTask flowTask) {
        List<String> permissionList = permissionList(SecurityUtil.getUser());
        flowTask.setPermissionList(permissionList);
        Page<FlowTaskVo> list = executeService.toDoPage(page, flowTask);
        List<Long> taskIds = StreamUtils.toList(list.getRecords(), FlowTaskVo::getId);
        List<User> userList = flowUserservice.getByAssociateds(taskIds);
        Map<Long, List<User>> map = StreamUtils.groupByKey(userList, User::getAssociated);
        for (FlowTaskVo taskVo : list.getRecords()) {
            if (!StrUtil.isEmptyIfStr(taskVo)) {
                List<User> users = map.get(taskVo.getId());
                if (CollectionUtils.isNotEmpty(users)) {
                    for (User user : users) {
                        if (UserType.APPROVAL.getKey().equals(user.getType())) {
                            if (StrUtil.isEmpty(taskVo.getApprover())) {
                                taskVo.setApprover("");
                            }
                            String name = getName(user.getProcessedBy());
                            if (StrUtil.isNotEmpty(name))
                                taskVo.setApprover(taskVo.getApprover().concat(name).concat(";"));
                        } else if (UserType.TRANSFER.getKey().equals(user.getType())) {
                            if (StrUtil.isEmpty(taskVo.getTransferredBy())) {
                                taskVo.setTransferredBy("");
                            }
                            String name = getName(user.getProcessedBy());
                            if (StrUtil.isNotEmpty(name))
                                taskVo.setTransferredBy(taskVo.getTransferredBy().concat(name).concat(";"));
                        } else if (UserType.DEPUTE.getKey().equals(user.getType())) {
                            if (StrUtil.isEmpty(taskVo.getDelegate())) {
                                taskVo.setDelegate("");
                            }
                            String name = getName(user.getProcessedBy());
                            if (StrUtil.isNotEmpty(name))
                                taskVo.setDelegate(taskVo.getDelegate().concat(name).concat(";"));
                        }
                    }
                }
            }
        }
        return R.ok(list.getRecords(), list.getTotal());
    }

    /**
     * 分页抄送任务列表
     * author：暗影
     */
    @SaCheckPermission("execute_copy")
    @GetMapping("/copyPage")
    public R copyPage(Page page, FlowTask flowTask) {
        List<String> permissionList = permissionList(SecurityUtil.getUser());
        flowTask.setPermissionList(permissionList);
        Page<FlowTaskVo> list = executeService.copyPage(page, flowTask);
        return R.ok(list.getRecords(), list.getTotal());
    }

    /**
     * 分页已办任务列表
     */
    @SaCheckPermission("execute_done")
    @GetMapping("/donePage")
    public R donePage(Page page, FlowHisTask flowHisTask) {
        List<String> permissionList = permissionList(SecurityUtil.getUser());
        flowHisTask.setPermissionList(permissionList);
        Page<FlowHisTaskVo> list = executeService.donePage(page, flowHisTask);
        Map<Long, String> userMap = StreamUtils.toMap(userService.list(), com.h5ve.system.entity.User::getId, com.h5ve.system.entity.User::getNickName);
        if (CollectionUtils.isNotEmpty(list.getRecords())) {
            for (FlowHisTaskVo hisTaskVo : list.getRecords()) {
                if (StrUtil.isNotEmpty(hisTaskVo.getApprover())) {
                    String name = getName(hisTaskVo.getApprover());
                    hisTaskVo.setApprover(name);
                }
                if (StrUtil.isNotEmpty(hisTaskVo.getCollaborator())) {
                    hisTaskVo.setCollaborator(userMap.get(Long.valueOf(hisTaskVo.getCollaborator())));
                }
            }
        }
        return R.ok(list.getRecords(), list.getTotal());
    }

    private String getName(String id) {
        Map<Long, String> userMap = StreamUtils.toMap(userService.list(), com.h5ve.system.entity.User::getId, com.h5ve.system.entity.User::getNickName);
        Map<Long, String> deptMap = StreamUtils.toMap(deptService.list(), Dept::getDeptId, Dept::getName);
        Map<Long, String> roleMap = StreamUtils.toMap(roleService.list(), Role::getId, Role::getName);
        if (!StrUtil.isEmptyIfNum(id)) {
            if (id.contains("user:")) {
                String name = userMap.get(Long.valueOf(id.replace("user:", "")));
                if (StrUtil.isNotEmpty(name)) {
                    return "用户:" + name;
                }
            } else if (id.contains("dept:")) {
                String name = deptMap.get(Long.valueOf(id.replace("dept:", "")));
                if (StrUtil.isNotEmpty(name)) {
                    return "部门:" + name;
                }
            } else if (id.contains("role")) {
                String name = roleMap.get(Long.valueOf(id.replace("role:", "")));
                if (StrUtil.isNotEmpty(name)) {
                    return "角色:" + name;
                }
            } else {
                String name = userMap.get(Long.valueOf(id));
                if (StrUtil.isNotEmpty(name)) {
                    return "用户:" + name;
                }
            }
        }
        return "";
    }


    /**
     * 查询已办任务历史记录
     */
    @SaCheckPermission("execute_history")
    @GetMapping("/doneList/{instanceId}")
    public R doneList(@PathVariable("instanceId") Long instanceId) {
        List<HisTask> flowHisTasks = hisTaskService.orderById().desc().list(new FlowHisTask().setInstanceId(instanceId));
        Map<Long, String> userMap =  StreamUtils.toMap(userService.list(), com.h5ve.system.entity.User::getId, com.h5ve.system.entity.User::getNickName);
        List<FlowHisTaskVo> flowHisTaskVos = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(flowHisTasks)) {
            for (HisTask hisTask : flowHisTasks) {
                if (StrUtil.isNotEmpty(hisTask.getApprover())) {
                    String name = getName(hisTask.getApprover());
                    hisTask.setApprover(name);
                }
                if (StrUtil.isNotEmpty(hisTask.getCollaborator())) {
                    hisTask.setCollaborator(userMap.get(Long.valueOf(hisTask.getCollaborator())));
                }
                FlowHisTaskVo flowHisTaskVo = new FlowHisTaskVo();
                BeanUtils.copyProperties(hisTask, flowHisTaskVo);
                flowHisTaskVos.add(flowHisTaskVo);
            }
        }
        return R.ok(flowHisTaskVos);
    }

    /**
     * 根据taskId查询代表任务
     *
     * @param taskId
     * @return
     */
    @GetMapping("/getTaskById/{taskId}")
    public R<Task> getTaskById(@PathVariable("taskId") Long taskId) {
        return R.ok(taskService.getById(taskId));
    }

    /**
     * 查询跳转任意节点列表
     */
    @SaCheckPermission("execute_doneList")
    @GetMapping("/anyNodeList/{instanceId}/{nodeCode}")
    public R<List<Node>> anyNodeList(@PathVariable("instanceId") Long instanceId
            , @PathVariable("nodeCode") String nodeCode) {
        Instance instance = insService.getById(instanceId);
        Node node = nodeService.getOne(FlowFactory.newNode().setDefinitionId(instance.getDefinitionId()).setNodeCode(nodeCode));
        if (FlowCons.SKIP_ANY_N.equals(node.getSkipAnyNode())) {
            return R.ok();
        }
        List<Node> nodeList = nodeService.list(FlowFactory.newNode().setDefinitionId(instance.getDefinitionId()));
        nodeList = StreamUtils.filter(nodeList, n -> (NodeType.isBetween(n.getNodeType())
                || NodeType.isEnd(n.getNodeType())) && !nodeCode.equals(n.getNodeCode()));
        return R.ok(nodeList);
    }

    /**
     * 处理非办理的流程交互类型
     *
     * @param warmFlowInteractiveTypeVo 要转办用户
     * @return 是否成功
     */
    @PostMapping("/interactiveType")
    public R<Boolean> interactiveType(WarmFlowInteractiveTypeVo warmFlowInteractiveTypeVo) {
        return R.ok(hhDefService.interactiveType(warmFlowInteractiveTypeVo));
    }

    /**
     * 交互类型可以选择的用户
     *
     * @param warmFlowInteractiveTypeVo 交互类型请求类
     * @return 是否成功
     */
    @GetMapping("/interactiveTypeSysUser")
    public R interactiveTypeSysUser(WarmFlowInteractiveTypeVo warmFlowInteractiveTypeVo) {
        H5veUser currentUser = SecurityUtil.getUser();
        Long userId = currentUser.getId();
        Integer operatorType = warmFlowInteractiveTypeVo.getOperatorType();
        List<com.h5ve.system.entity.User> list;
        Long taskId = warmFlowInteractiveTypeVo.getTaskId();
        List<User> users = flowUserservice.listByAssociatedAndTypes(taskId);
        if (!Objects.equals(CooperateType.REDUCTION_SIGNATURE.getKey(), operatorType)) {
            List<String> userIds = StreamUtils.toList(users, User::getProcessedBy);
            warmFlowInteractiveTypeVo.setUserIds(userIds);
            list = userService.selectNotUserList(warmFlowInteractiveTypeVo);
        } else {
            List<String> userIds = StreamUtils.toList(users, User::getProcessedBy);
            warmFlowInteractiveTypeVo.setUserIds(userIds);
            list = userService.selectUserList(warmFlowInteractiveTypeVo);
            list = StreamUtils.filter(list, sysUser -> !Objects.equals(userId, sysUser.getId()));
        }
        return R.ok(list);
    }

    /**
     * 获取权限
     *
     * @param sysUser 登陆用户
     * @return 权限列表
     */
    public static List<String> permissionList(H5veUser sysUser) {
        List<String> permissionList = StreamUtils.toList(new ArrayList<>(sysUser.getRoles()), role -> "role:" + role.replace(CommonConstants.ROLE, ""));
        permissionList.add(String.valueOf(sysUser.getId()));
        permissionList.add("dept:" + sysUser.getDeptId());
        log.info("当前用户所有权限[{}]", permissionList);
        return permissionList;
    }
}
